GameLoader.addGameData("pipeflow", {
    sensors: ["orientationGamma"],
    orientationGamma: 0,
    run: function(stage) {
        var canvas = new Element("canvas#canvas[width=500][height=500]", {
            text: "Sorry, your browser doesn't support canvas."
        });
        stage.empty().grab(canvas);
        this.canvasContext = canvas.getContext("2d");
        this.setDefaultData();
        this.interval = this.paint.periodical(1000/24, this);
    },
    message: function(message) {
        this.orientationGamma = message.orientationGamma;
    },
    interrupt: function() {
        if(!this.gameover) {
            clearInterval(this.interval);
            this.timeOffset = Date.now() - this.start;
        }
    },
    resume: function() {
        if(!this.gameover) {
            this.start = Date.now() - this.timeOffset;
            this.interval = this.paint.periodical(1000/24, this);
        }
    },
    setDefaultData: function() {
        this.gameover = false;
        this.start = Date.now() - 1;

        this.backgroundCircles = [50, 100, 150, 200, 250, 300];

        this.walls = [];
        this.nextWall = Date.now();

        this.backgroundGradient = this.canvasContext.createRadialGradient(250, 250, 0, 250, 250, 350);
        this.backgroundGradient.addColorStop(0.00, "#000000");
        this.backgroundGradient.addColorStop(0.05, "#101103");
        this.backgroundGradient.addColorStop(0.10, "#354024");
        this.backgroundGradient.addColorStop(0.25, "#5B7046");
        this.backgroundGradient.addColorStop(0.40, "#819F67");
        this.backgroundGradient.addColorStop(0.60, "#A6CF89");
        this.backgroundGradient.addColorStop(1.00, "#CCFFAA");

        this.lineGradient = this.canvasContext.createRadialGradient(0, 0, 0, 0, 0, 350);
        this.lineGradient.addColorStop(0.00, "#000000");
        this.lineGradient.addColorStop(0.05, "#001100");
        this.lineGradient.addColorStop(0.10, "#214010");
        this.lineGradient.addColorStop(0.25, "#337028");
        this.lineGradient.addColorStop(0.40, "#459F2B");
        this.lineGradient.addColorStop(0.60, "#56CF39");
        this.lineGradient.addColorStop(0.90, "#69FF46");
        this.lineGradient.addColorStop(1.00, "#CCFFAA");
    },
    paint: function() {
        var time = Date.now();

        this.paintPipe(time);
        this.paintObjects(time);
        this.paintPoints();
        if(this.gameover) {
            this.paintGameOver();
        }
    },
    getOffset: function(position, time) {
        return (position + 1) * ((time - this.start - Math.sqrt(Math.floor(time - this.start))) / 1000000 + 0.005);
    },
    paintPipe: function(time) {
        var context = this.canvasContext;
        context.save();

        context.fillStyle = this.backgroundGradient;
        context.fillRect(0, 0, 500, 500);

        context.translate(250, 250);
        this.paintBackgroundCircles(time);
        this.paintBackgroundLines();

        context.restore();
    },
    paintBackgroundCircles: function(time) {
        var context = this.canvasContext;
        context.strokeStyle = this.lineGradient;
        this.backgroundCircles.each(function(position, index, circles) {
            position = circles[index] = (position-30 + this.getOffset(position, time)) % 320 + 30;
            context.beginPath();
            context.arc(0, 0, position, 0, Math.PI*2);
            context.stroke();
        }, this);
    },
    paintBackgroundLines: function() {
        var context = this.canvasContext;
        context.save();

        context.rotate(Math.PI/180 * (this.orientationGamma + 20));
        context.strokeStyle = this.lineGradient;

        for(var i = 0; i < 9; i++) {
            context.rotate(Math.PI/4.5);
            context.beginPath();
            context.moveTo(0, 0);
            context.lineTo(0, 350);
            context.stroke();
        }

        context.restore();
    },
    paintObjects: function(time) {
        this.createWalls(time);
        this.moveWalls(time);

        var context = this.canvasContext;
        context.save();

        context.translate(250, 250);
        context.rotate(Math.PI/180 * this.orientationGamma);

        var isPlayerPainted = false;
        this.walls.each(function(wall) {
            if(wall.position > 225 && !isPlayerPainted) {
                isPlayerPainted = true;
                context.restore();

                this.checkCollision(wall);
                this.paintPlayer();

                context.save();
                context.translate(250, 250);
                context.rotate(Math.PI/180 * this.orientationGamma);
            }

            var gradient = context.createRadialGradient(0, 0, 0, 0, 0, 250);
            gradient.addColorStop(0, "rgba(0,0,0,0.7)");
            gradient.addColorStop(1, wall.color);
            context.fillStyle = gradient;

            context.beginPath();
            context.arc(0, 0, wall.position, wall.startAngle, wall.endAngle);
            context.arc(0, 0, wall.position - (80 * (wall.position / 200)), wall.endAngle, wall.startAngle, true);
            context.fill();
        }, this);

        context.restore();
        
        if(!isPlayerPainted) {
            this.paintPlayer();
        }
    },
    createWalls: function(time) {
        if(this.nextWall < time) {
            var wall = {};
            wall.color = "rgba(" + Number.random(0, 255) + "," + Number.random(0, 255) + "," + Number.random(0, 255) + ",0.9)";
            wall.startAngle = Math.PI * 2 * Math.random();
            wall.endAngle = wall.startAngle + Math.PI * 2 * (Number.random(50, 80) / 100);
            wall.position = 0;

            this.walls.unshift(wall);
            
            this.nextWall = time + 50/this.getOffset(this.walls[0].position, time);

        }
    },
    moveWalls: function(time) {
        this.walls.each(function(wall) {
            wall.position += this.getOffset(wall.position, time);
        }, this);
        this.walls = this.walls.filter(function(wall) {
            return wall.position < 450;
        });
    },
    paintPlayer: function() {
        var context = this.canvasContext;
        context.save();
        context.fillStyle = "#ffffff";
        if(this.gameover) {
            context.fillStyle = "#ff0000";
        }
        context.beginPath();
        context.arc(250, 450, 30, 0, Math.PI*2);
        context.fill();
        context.restore();
    },
    checkCollision: function(wall) {
        if(!wall.collisionChecked) {
            wall.collisionChecked = true;
            
            var startAngle = wall.startAngle;
            var endAngle = wall.endAngle;
            var playerGrad = (90 - this.orientationGamma + 360) % 360;
            var playerAngle = Math.PI / 180 * playerGrad;
            var playerAngle360 = (playerGrad+360) / 180 * Math.PI;

            if(playerAngle+0.125 > startAngle && playerAngle-0.125 < endAngle || playerAngle360+0.125 > startAngle && playerAngle360-0.125 < endAngle) {
                this.gameover = true;
                clearInterval(this.interval);
            }
        }
    },
    paintPoints: function() {
        this.points = String.from(Math.floor(Math.sqrt((Date.now() - this.start))) - 90);
        if(this.points >= 0) {
            var context = this.canvasContext;
            context.font = "20px Verdana, Arial, sans-serif";
            var width = context.measureText("Punkte: " + this.points).width;
            context.fillText("Punkte: " + this.points, 480 - width, 20);
        }
    },
    paintGameOver: function() {
        var context = this.canvasContext;
        context.fillStyle = "#56CF39";
        context.fillRect(100, 150, 300, 200);

        context.fillStyle = "#000000";

        context.font = "50px Verdana, Arial, sans-serif";
        var width = context.measureText("Game Over").width;
        context.fillText("Game Over", 250 - (width/2), 200);

        context.font = "25px Verdana, Arial, sans-serif";
        width = context.measureText("Sie haben").width;
        context.fillText("Sie haben", 250 - (width/2), 240);

        context.font = "50px Verdana, Arial, sans-serif";
        width = context.measureText(this.points).width;
        context.fillText(this.points, 250 - (width/2), 290);

        context.font = "25px Verdana, Arial, sans-serif";
        width = context.measureText("Punkte erreicht.").width;
        context.fillText("Punkte erreicht.", 250 - (width/2), 325);
    }
});